#include <math.h>
#include <algorithm>
#include <set>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <string>
#include <cstring>
#include <functional>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <chrono>
#include <climits>
using namespace std ;
#define ld long double
#define int long long
#define ii pair<int,int>
#define _ ios_base::sync_with_stdio(false) ;cin.tie(NULL);cout.tie(NULL);
#define dbg(x) cerr << #x << " is " << x << endl;
#define ms(x,a) memset(x,(int)(a),sizeof(x))
#define all(x) (x).begin(), (x).end()
#define sz(x) ((int)(x).size())
#define vi vector<int >
#define pb push_back
#define endl '\n'
#define ff first
#define ss second
const int N = 2e5+7 ;
const int INF = 1e9 ;
const int MOD = INF + 7 ;
string s ;

struct SCC{
	vector<vector<int> > vec;
	int index;
	vector<int> idx;
	vector<int> lowlink;
	vector<bool> onstack;
	stack<int> s;
	vector<int> sccidx;
	int scccnt;
	vi topo;
	
	//lower sccidx means appear later
	void init(int n)
	{
		idx.assign(n,-1);
		index = 0;
		onstack.assign(n,0);
		lowlink.assign(n,INF);
		while(!s.empty()) s.pop();
		sccidx.assign(n,-1);
		scccnt = 0;
		vec.clear();
		topo.clear();
		vec.resize(n);
	}
	
	void addedge(int u, int v) //u -> v
	{
		vec[u].pb(v);
	}
	
	void connect(int u)
	{
		idx[u] = index;
		lowlink[u] = index;
		index++;
		s.push(u);
		onstack[u] = true;
		for(int i = 0; i < vec[u].size(); i++)
		{
			int v = vec[u][i];
			if(idx[v] == -1)
			{
				connect(v);
				lowlink[u] = min(lowlink[u], lowlink[v]);
			}
			else if(onstack[v])
			{
				lowlink[u] = min(lowlink[u], idx[v]);
			}
		}
		if(lowlink[u] == idx[u])
		{
			while(1)
			{
				int v = s.top();
				s.pop();
				onstack[v] = false;
				sccidx[v] = scccnt;
				if(v == u) break;
			}
			scccnt++;
		}
	}
	
	void tarjan()
	{
		for(int i = 0; i < vec.size(); i++)
		{
			if(idx[i] == -1)
			{
				connect(i);
			}
		}
	}
	
	void toposort() //if graph is a DAG and i just want to toposort
	{
		tarjan();
		int n = vec.size();
		topo.resize(n);
		vector<ii> tmp;
		for(int i = 0; i < n; i++)
		{
			tmp.pb({sccidx[i],i});
		}
		sort(tmp.begin(),tmp.end());
		reverse(tmp.begin(),tmp.end());
		for(int i = 0; i < n; i++)
		{
			topo[i]=tmp[i].ss;
		}
	}
};



int dp[111111];
vi adj[111111];
/* Print pair */
 template <typename T,typename S>
 ostream & operator << (ostream &os , const pair<T,S> &v) {
     os << "(" ;
     os << v.first << "," << v.second << ")" ;
     return os ;
 }
 /* Print vector */
 template <typename T>
 ostream & operator << (ostream &os , const vector<T> &v) {
     os << "[" ;
     int sz = v.size() ;
     for(int i = 0 ; i < sz ; ++i) {
         os << v[i] ;
         if(i!=sz-1)os << "," ;
     }
     os << "]\n" ;
     return os ;
 }
 /* Print set */
 template <typename T>
 ostream & operator << (ostream &os , const set<T> &v) {
     T last = *v.rbegin() ;
     os << "[" ;
     for(auto it : v) {
         os << it  ;
         if(it != last) os << "," ;
     }
     os << "]\n" ;
     return os ;
 }
 /* Print Map */
 template <typename T,typename S>
 ostream & operator << (ostream &os , const map<T,S> &v) {
     for(auto it : v) {
         os << it.first << " : " << it.second << "\n" ;
     }
     return os ;
 }
 //debug
 #define TRACE
 
 #ifdef TRACE
 #define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
 template <typename Arg1>
 void __f(const char* name, Arg1&& arg1){
 cerr << name << " : " << arg1 << endl;
 }
 template <typename Arg1, typename... Args>
 void __f(const char* names, Arg1&& arg1, Args&&... args){
 const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
 }
 #else
 #define trace(...)
 #endif
 
  

int32_t main(){
	ios_base::sync_with_stdio(0); cin.tie(0);
	int n,m; cin>>n>>m;
	SCC scc; scc.init(n); vector<ii> E;
	for(int i=0;i<m;i++)
	{
		int u,v; cin>>u>>v; u--; v--; scc.addedge(u,v); E.pb({u,v});
	}
	scc.tarjan();
	for(int i=0;i<m;i++)
	{
		int u=E[i].ff; int v=E[i].ss;
		adj[scc.sccidx[u]].pb(scc.sccidx[v]);
	//	trace(u,v,scc.sccidx[u], scc.sccidx[v]) ;
	}
	int ans=0;
	for(int i=0;i<n;i++)
	{
		dp[i]=1;
		for(int v:adj[i])
		{
			dp[i]=max(dp[i],dp[v]+1);
		}
		ans=max(ans,dp[i]);
	}
	cout<<ans-1<<'\n';
}

Measured memory_bytes: 17776